<template>
  <div
    class="biz-float-icon"
    @pointerdown.left="start"
    @pointerup="end" 
    @pointercancel="end"
    @pointermove="dragging ? move($event) : null"
    @touchstart.prevent="" 
    @dragstart.prevent=""
    :class="{dragging}"
    :style="{
      left: x + 'px',
      top: y + 'px'
    }"
  >
    <slot />
  </div>
</template>

<script>
/** 
 * @description: 悬浮球
 * 当前文件的代码来源于: https://www.cnblogs.com/deng-jie/p/16408876.html
 * 直接复制粘贴的。
*/
export default {
  name: 'BizFloatIcon',
  props: {
    x: {
      type: Number,
      default: 0
    },
    y: {
      type: Number,
      default: 0
    },
    topSafeArea: {
      type: Number,
      default: 0,
    },
    leftSafeArea: {
      type: Number,
      default: 0,
    },
    rightSafeArea: {
      type: Number,
      default: 0,
    },
    bottomSafeArea: {
      type: Number,
      default: 0,
    }
  },
  data() {
    return {
      dragging: null,
      eventTypeEnum: {
        start: 'start',
        end: 'end',
        move: 'move'
      },
      dragEvents: []
    };
  },
  created() {
    
  },
  mounted() {
    window.addEventListener('resize', this.handleResize);
  },
  beforeUnmount() {
    window.removeEventListener('resize', this.handleResize);
  },
  methods: {
    handleResize() {
      
    },
    start(event) {
      
      this.dragEvents.push(event);
      
      if (event.ctrlKey) {
        return;
      }
      
      let { x, y } = this.convertStartPoint(event);
      
      this.dragging = {
        dx: this.x - x, 
        dy: this.y - y
      };
      
      event.currentTarget.setPointerCapture(event.pointerId);
      
    },
    end(event) {
      
      this.dragEvents.push(event);
      this.dragging = null;
      
      // 如果只有 开始 和 结束 两个事件，没有移动事件，那么就是点击事件
      if (this.dragEvents.length <= 2) {
        this.$emit('click');
      } else {
        // 如果有移动事件，那么就是拖动事件，拖动结束后，将图标放在屏幕右侧靠边
        const x = window.innerWidth - this.rightSafeArea - this.$el.offsetWidth;
        this.$emit('updateX', x);
        this.$emit('updateY', this.y);
        this.$emit('dragend');
      }
      
      this.dragEvents = [];
    },
    move(event) {
      
      this.dragEvents.push(event);
      
      let { x, y } = this.convertMovePoint(event);
      
      this.$emit('updateX', x);
      this.$emit('updateY', y);
      
    },
    convertStartPoint(event) {
      
      const point = {
        x: event.clientX,
        y: event.clientY
      }
      
      return point
      
    },
    convertMovePoint(event) {
      
      // 当前元素拖动的起始点 X 的偏移量 
      const dragX = this.dragging.dx
      // 当前元素拖动的起始点 Y 的偏移量
      const dragY = this.dragging.dy
      
      // 当前元素拖动的起始点 X 的绝对值
      const absDragX = Math.abs(dragX)
      // 当前元素拖动的起始点 Y 的绝对值
      const absDragY = Math.abs(dragY)
      
      // 当前鼠标的 X 坐标 - 当前元素拖动的起始点 X 的偏移量
      let x = event.clientX - absDragX;
        // 当前鼠标的 Y 坐标 - 当前元素拖动的起始点 Y 的偏移量
      let y = event.clientY - absDragY;
      
      // 如果实际的 X 坐标 小于等于 左边安全区域的宽度，那么就让 X 坐标等于 左边安全区域的宽度
      if (x <= this.leftSafeArea) {
        x = this.leftSafeArea;
      }
      
      // 如果实际的 Y 坐标 小于等于 上边安全区域的高度，那么就让 Y 坐标等于 上边安全区域的高度
      if (y <= this.topSafeArea) {
        y = this.topSafeArea;
      }
      
      // 如果实际的 X 坐标 大于等于 (视口的宽度 - 右边安全区域的宽度 - 当前元素的宽度)，那么就让 X 坐标等于 (视口的宽度 - 右边安全区域的宽度 - 当前元素的宽度)
      if (x >= (window.innerWidth - this.rightSafeArea - this.$el.offsetWidth)) {
        x = window.innerWidth - this.rightSafeArea - this.$el.offsetWidth;
      }
      
      // 如果实际的 Y 坐标 大于等于 (视口的高度 - 下边安全区域的高度 - 当前元素的高度)，那么就让 Y 坐标等于 (视口的高度 - 下边安全区域的高度 - 当前元素的高度)
      if (y >= (window.innerHeight - this.bottomSafeArea - this.$el.offsetHeight)) {
        y = window.innerHeight - this.bottomSafeArea - this.$el.offsetHeight;
      }
      
      const point = {
        x: x,
        y: y
      }
      
      return point
    }
  }
};
</script>
<style lang="scss">
  .biz-float-icon {
    
    position: fixed;
    width: 60px;
    height: 60px;
    cursor: grab;
    
    &.dragging {
      cursor: grabbing;
    }
    
  }
</style>